﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "ElementId.h"
#include "RuntimeId.h"
#include "IPropertyWidget.h"
#include "IUiDocumentEvent.h"
#include "IUiViewEventHandler.h"
#include "IElementsChangeEventHandler.h"
#include "ISelectionChangeEventHandler.h"

#include "UIPlatform.h"
#include <PropertyWidget.h>
#include "UiEventHandlerMacro.h"

namespace gcmp
{
    class IElement;
    class IDocument;
    class IParameter;
    class IUiView;
    class IPropertyPanelEvent;
    class IParameterValueStorage;
    class IUserTransaction;
    class IEndOfTransactionProcessor;
}

namespace Sample
{
    class PropertyPanelEvent;
    class PropertyPaletteEventHandler;
    class PropertyPaletteUiDocEventHandler;
    class PropertyPaletteUiViewEventHandler;
    class PropertyPaletteSelectionChangeEventHandler;
}

class  UIPLATFORM_EXPORT PropertyPalette : public Sample::CPropertyWidget, public gcmp::IPropertyWidget
{
    Q_OBJECT

public:
    PropertyPalette();
    virtual ~PropertyPalette();
    //显示属性面板
    static void DisplayPanel();
    //获取属性面板的唯一实例
    static PropertyPalette* GetPropertyPalette();
    QSize sizeHint() const;

    //继承自IPropertyWidget
public:
    virtual void Refresh(bool bRebuildPropertyWidget) override;
    virtual void RefreshAll() override;
    virtual void SetEnabled(bool bEnable) override { Sample::CPropertyWidget::setEnabled(bEnable); }

    virtual void UpdateStatus() override;
    virtual gcmp::IPropertyPanelEvent* GetInputEvent() override;

    bool RefreshByParameterValueStorage(gcmp::IParameterValueStorage *pCurrentParamValue, int parameterDefinitionId);

    void SetPropertyTableCanBeUpdated(bool canOrNot) { m_canPropertyTableBeUpdated = canOrNot; }
public:
    virtual void SetDefaultElementId(const gcmp::ElementId& idDefaultElement) override;

    virtual void SetPreSetElementId(const gcmp::ElementId& elementId) override;
    virtual const gcmp::ElementId GetPreSetElementId() const override;

    std::wstring GetComponentTypeChangedEventId() const;
    std::wstring GetComponentTypeModifiedPropertyEventId() const;

    void CheckDocSwitched();
private:

    // 点击不同的构件类型触发的事件
    virtual void OnSelectComponentType(const Sample::CComponentTypeItem *pComponentTypeItem) override;

    //添加构件类型按钮点击回调
    virtual void OnAddComponentTypeBottonClick()override;

    //编辑构件类型按钮点击回调
    virtual void OnModifyComponentBottonClick()override;

    // 应用按钮点击处理
    virtual void OnApply() override;

    // 编辑修改属性触发的事件
    virtual void OnPropertyValueChanged(int groupIndex, int propertyIndex) override;

protected:
    virtual void showEvent(QShowEvent *event)override;

protected slots:
    void OnPropertyBindButtonClicked(int uniquiID);
    void onPropertyEditButtonClicked(int uniquiID);
    void OnDropDownListIndexChange(int groupIndex, int propertyIndex);

private:
    //监听Element修改
    void AttachElementChangeObserver(gcmp::IUiView* pUIView);
    void DetachElementChangeObserver(gcmp::IUiView* pUIView);

private:
    void UpdateComponentType();
    void UpdateViewVisual();
    void UpdatePropertyTable(bool bRebuild = false);
    void SetPropertyItemValue(Sample::CPropertyItem* pItem, const gcmp::IParameter* param, const std::vector<gcmp::ElementId> &elementIds, bool isMultiValue);

    // 清空面板类型显示
    void ClearComponentType();
    // 显示视图类型信息
    void ShowViewComponentType();
    // 从属性表界面修改属性参数更新到Element（提交事务)
    void UpdatePropertyTableToElement(); 
    // 从属性表界面修改属性项目更新到Element
    bool UpdatePropertyItemToElement(int groupIndex, int propertyIndex);

    // 获得当前选择集Elements
    std::vector<gcmp::ElementId> GetSelectedElements();
    // 获取其他属性表显示Elements
    std::vector<gcmp::ElementId> GetSourceElements();

    const std::unordered_set<gcmp::ElementId, gcmp::ElementIdHash> & GetSelectedElementsFast();
    const std::unordered_set<gcmp::ElementId, gcmp::ElementIdHash> & GetSourceElementsFast();

    //辅助函数
private:
    gcmp::IDocument* GetDocument();
    void GetShowElements(std::vector<gcmp::ElementId>& selElements);
    bool CheckParameterValid(Sample::CPropertyItem* pItem, const gcmp::IParameter* param, const std::vector<gcmp::ElementId>& selElements);
    bool UpdatePropertyItemToElementParameter(Sample::CPropertyItem* pItem, gcmp::IElement* pElement, const std::vector<gcmp::ElementId>& selElements, bool& bCommitAlways, bool& error);

    bool SaveParamValueToElement(gcmp::IElement* pElement, gcmp::IParameter* param, gcmp::OwnerPtr<gcmp::IParameterValueStorage> &opCurrentParamValue, bool &bParameterChanged);

    bool UpdatePresetParamValue(bool bParameterChanged, gcmp::IElement* pElement, gcmp::IParameter* param);

    bool GetCurrentParamValue(const gcmp::IParameter* param, Sample::CPropertyItem* pItem, const std::vector<gcmp::ElementId> &elementIds, gcmp::OwnerPtr<gcmp::IParameterValueStorage> &opCurrentParamValue, bool &bCommitNow);

    bool IsDockTopWidget();

    void SetStatusOfAddAndModifyButton();
    void SetStatusOfComponentTypeComboBox();
    bool SelectedElementsAreSameCategory(std::vector<gcmp::ElementId>& selElements);

    typedef std::vector<std::pair<std::wstring/*group name*/, 
        std::vector<gcmp::OwnerPtr<gcmp::IParameter>> /*parameter within the group*/> > GroupParametersArray;
    void GroupAndSortParameters(gcmp::IDocument* pDocument, const gcmp::IElement* pElement, const std::vector<gcmp::ElementId>& selElements,
        const std::vector<gcmp::OwnerPtr<gcmp::IParameter>>& commonParams, const std::vector<bool>& paramMultiVals,
        GroupParametersArray& outGroupParameters, std::map<int, bool>& outParamDefIdToIsParamMultiVals) const;

private:
    bool    m_isTopVisible; // 标示是否在层叠浮动窗口的最上层
    bool    m_isNeedUpdate; // 是否需要更新(用于连续修改延时更新）
    Int64   m_endOfTransactionProcessorId;
    gcmp::OwnerPtr<gcmp::IUserTransaction>                m_upUserTransaction;  
    gcmp::OwnerPtr<gcmp::IElementsChangeEventHandler>    m_elementChangeObserver;       //有对象改变（监听）
    gcmp::OwnerPtr<Sample::PropertyPanelEvent>             m_inputEvent;                  //用户修改属性表事件(对外通知）
    gcmp::OwnerPtr<gcmp::IUiDocumentEventHandler>        m_uiDocumentEventHandler;      //UiDoc事件（监听）
    gcmp::OwnerPtr<gcmp::IUiViewEventHandler>            m_uiViewEventHandler;          //UiView事件（监听）
    gcmp::OwnerPtr<gcmp::ISelectionChangeEventHandler>   m_selectionChangeEventHandler; //选择集改变（监听）

    friend class SelElementChangeObserver;
    friend class EndOfTransactionProcessorPropertyPalette;
    friend class Sample::PropertyPaletteEventHandler;
    friend class Sample::PropertyPaletteUiDocEventHandler;
    friend class Sample::PropertyPaletteUiViewEventHandler;
    friend class Sample::PropertyPaletteSelectionChangeEventHandler;;
    friend class ModelViewDlg;

    gcmp::ElementId m_defaultElementId;
    gcmp::ElementId m_tmpPreSetElementId;        // 用于预设参数的临时构件。
    gcmp::RuntimeId m_curUiDocId;
    bool m_bTransactionIsCommitting;

    bool m_canPropertyTableBeUpdated;
};

